@using System
@using System.Collections.Generic
@using System.Linq
@using System.Threading.Tasks
@using DiscordChatExporter.Core.Discord.Data
@using DiscordChatExporter.Core.Discord.Data.Embeds
@using DiscordChatExporter.Core.Markdown.Parsing
@using DiscordChatExporter.Core.Utils.Extensions

@inherits RazorBlade.HtmlTemplate

@functions {
    public required ExportContext Context { get; init; }

    public required IReadOnlyList<Message> Messages { get; init; }
}

@{
    ValueTask<string> ResolveAssetUrlAsync(string url) =>
        Context.ResolveAssetUrlAsync(url, CancellationToken);

    string FormatDate(DateTimeOffset instant, string format = "g") =>
        Context.FormatDate(instant, format);

    async ValueTask<string> FormatMarkdownAsync(string markdown) =>
        Context.Request.ShouldFormatMarkdown
            ? await HtmlMarkdownVisitor.FormatAsync(Context, markdown, true, CancellationToken)
            : markdown;

    async ValueTask<string> FormatEmbedMarkdownAsync(string markdown) =>
        Context.Request.ShouldFormatMarkdown
            ? await HtmlMarkdownVisitor.FormatAsync(Context, markdown, false, CancellationToken)
            : markdown;
}

<div class="chatlog__message-group">
@foreach (var (message, i) in Messages.WithIndex())
{
    var isFirst = i == 0;

    var authorMember = Context.TryGetMember(message.Author.Id);
    var authorColor = Context.TryGetUserColor(message.Author.Id);
    var authorDisplayName = message.Author.IsBot
        ? message.Author.DisplayName
        : authorMember?.DisplayName ?? message.Author.DisplayName;

    <div id="chatlog__message-container-@message.Id" class="chatlog__message-container @(message.IsPinned ? "chatlog__message-container--pinned" : null)" data-message-id="@message.Id">
        <div class="chatlog__message">
            @* System notification *@
            @if (message.IsSystemNotification)
            {
                <div class="chatlog__message-aside">
                    <svg class="chatlog__system-notification-icon">
                        @{
                            var icon = message.Kind switch {
                                MessageKind.RecipientAdd => "join-icon",
                                MessageKind.RecipientRemove => "leave-icon",
                                MessageKind.Call => "call-icon",
                                MessageKind.ChannelNameChange => "pencil-icon",
                                MessageKind.ChannelIconChange => "pencil-icon",
                                MessageKind.ChannelPinnedMessage => "pin-icon",
                                MessageKind.GuildMemberJoin => "join-icon",
                                MessageKind.ThreadCreated => "thread-icon",
                                _ => "pencil-icon"
                            };
                        }

                        <use href="#@icon"></use>
                    </svg>
                </div>

                <div class="chatlog__message-primary">
                    @* Author name *@
                    <span class="chatlog__system-notification-author" style="@(authorColor is not null ? $"color: rgb({authorColor.Value.R}, {authorColor.Value.G}, {authorColor.Value.B})" : null)" title="@message.Author.FullName" data-user-id="@message.Author.Id">@authorDisplayName</span>

                    @* Space out the content *@
                    <span> </span>

                    @* System notification content *@
                    <span class="chatlog__system-notification-content">
                        @if (message.Kind == MessageKind.RecipientAdd && message.MentionedUsers.Any())
                        {
                            <span>added </span>
                            <a class="chatlog__system-notification-link" title="@message.MentionedUsers.First().FullName">@message.MentionedUsers.First().DisplayName</a>
                            <span> to the group.</span>
                        }
                        else if (message.Kind == MessageKind.RecipientRemove && message.MentionedUsers.Any())
                        {
                            if (message.Author.Id == message.MentionedUsers.First().Id)
                            {
                                <span>left the group.</span>
                            }
                            else
                            {
                                <span>removed </span>
                                <a class="chatlog__system-notification-link" title="@message.MentionedUsers.First().FullName">@message.MentionedUsers.First().DisplayName</a>
                                <span> from the group.</span>
                            }
                        }
                        else if (message.Kind == MessageKind.Call)
                        {
                            <span>started a call that lasted @(((message.CallEndedTimestamp ?? message.Timestamp) - message.Timestamp).TotalMinutes.ToString("n0", Context.Request.CultureInfo)) minutes</span>
                        }
                        else if (message.Kind == MessageKind.ChannelNameChange)
                        {
                            <span>changed the channel name: </span>
                            <span class="chatlog__system-notification-link">@message.Content</span>
                        }
                        else if (message.Kind == MessageKind.ChannelIconChange)
                        {
                            <span>changed the channel icon.</span>
                        }
                        else if (message.Kind == MessageKind.ChannelPinnedMessage && message.Reference is not null)
                        {
                            <span>pinned </span>
                            <a class="chatlog__system-notification-link" href="#chatlog__message-container-@message.Reference.MessageId">a message</a>
                            <span> to this channel.</span>
                        }
                        else if (message.Kind == MessageKind.ThreadCreated)
                        {
                            <span>started a thread.</span>
                        }
                        else if (message.Kind == MessageKind.GuildMemberJoin)
                        {
                            <span>joined the server.</span>
                        }
                        else
                        {
                            <span>@message.Content.ToLowerInvariant()</span>
                        }
                    </span>

                    @* Timestamp *@
                    <span class="chatlog__system-notification-timestamp" title="@FormatDate(message.Timestamp, "f")">
                        <a href="#chatlog__message-container-@message.Id">@FormatDate(message.Timestamp)</a>
                    </span>
                </div>
            }
            // Regular message
            else
            {
                <div class="chatlog__message-aside">
                    @if (isFirst)
                    {
                        // Reply symbol
                        if (message.IsReplyLike)
                        {
                            <div class="chatlog__reply-symbol"></div>
                        }

                        // Avatar
                        <img class="chatlog__avatar" src="@await ResolveAssetUrlAsync(authorMember?.AvatarUrl ?? message.Author.AvatarUrl)" alt="Avatar" loading="lazy">
                    }
                    else
                    {
                        <div class="chatlog__short-timestamp" title="@FormatDate(message.Timestamp, "f")">@FormatDate(message.Timestamp, "t")</div>
                    }
                </div>

                <div class="chatlog__message-primary">
                    @if (isFirst)
                    {
                        // Message referenced by the reply
                        if (message.IsReplyLike)
                        {
                            <div class="chatlog__reply">
                                @if (message.ReferencedMessage is not null)
                                {
                                    var referencedUserMember = Context.TryGetMember(message.ReferencedMessage.Author.Id);
                                    var referencedUserColor = Context.TryGetUserColor(message.ReferencedMessage.Author.Id);
                                    var referencedUserDisplayName = message.ReferencedMessage.Author.IsBot
                                        ? message.ReferencedMessage.Author.DisplayName
                                        : referencedUserMember?.DisplayName ?? message.ReferencedMessage.Author.DisplayName;

                                    <img class="chatlog__reply-avatar" src="@await ResolveAssetUrlAsync(referencedUserMember?.AvatarUrl ?? message.ReferencedMessage.Author.AvatarUrl)" alt="Avatar" loading="lazy">
                                    <div class="chatlog__reply-author" style="@(referencedUserColor is not null ? $"color: rgb({referencedUserColor.Value.R}, {referencedUserColor.Value.G}, {referencedUserColor.Value.B})" : null)" title="@message.ReferencedMessage.Author.FullName">@referencedUserDisplayName</div>
                                    <div class="chatlog__reply-content">
                                        <span class="chatlog__reply-link" onclick="scrollToMessage(event, '@message.ReferencedMessage.Id')">
                                            @if (!string.IsNullOrWhiteSpace(message.ReferencedMessage.Content) && !message.ReferencedMessage.IsContentHidden())
                                            {
                                                <!--wmm:ignore-->@Html.Raw(await FormatEmbedMarkdownAsync(message.ReferencedMessage.Content))<!--/wmm:ignore-->
                                            }
                                            else if (message.ReferencedMessage.Attachments.Any() || message.ReferencedMessage.Embeds.Any())
                                            {
                                                <em>Click to see attachment</em>
                                                <span>🖼️</span>
                                            }
                                            else
                                            {
                                                <em>Click to see original message</em>
                                            }
                                        </span>

                                        @if (message.ReferencedMessage.EditedTimestamp is not null)
                                        {
                                            <span class="chatlog__reply-edited-timestamp" title="@FormatDate(message.ReferencedMessage.EditedTimestamp.Value, "f")">(edited)</span>
                                        }
                                    </div>
                                }
                                else if (message.Interaction is not null)
                                {
                                    var interactionUserMember = Context.TryGetMember(message.Interaction.User.Id);
                                    var interactionUserColor = Context.TryGetUserColor(message.Interaction.User.Id);
                                    var interactionUserDisplayName = message.Interaction.User.IsBot
                                        ? message.Interaction.User.DisplayName
                                        : interactionUserMember?.DisplayName ?? message.Interaction.User.DisplayName;

                                    <img class="chatlog__reply-avatar" src="@await ResolveAssetUrlAsync(interactionUserMember?.AvatarUrl ?? message.Interaction.User.AvatarUrl)" alt="Avatar" loading="lazy">
                                    <div class="chatlog__reply-author" style="@(interactionUserColor is not null ? $"color: rgb({interactionUserColor.Value.R}, {interactionUserColor.Value.G}, {interactionUserColor.Value.B})" : null)" title="@message.Interaction.User.FullName">@interactionUserDisplayName</div>
                                    <div class="chatlog__reply-content">
                                        used /@message.Interaction.Name
                                    </div>
                                }
                                else
                                {
                                    <div class="chatlog__reply-unknown">
                                        Original message was deleted or could not be loaded.
                                    </div>
                                }
                            </div>
                        }

                        // Header
                        <div class="chatlog__header">
                            @* Author name *@
                            <span class="chatlog__author" style="@(authorColor is not null ? $"color: rgb({authorColor.Value.R}, {authorColor.Value.G}, {authorColor.Value.B})" : null)" title="@message.Author.FullName" data-user-id="@message.Author.Id">@authorDisplayName</span>

                            @* Bot tag *@
                            @if (message.Author.IsBot)
                            {
                                // For cross-posts, the BOT tag is replaced with the SERVER tag
                                if (message.Flags.HasFlag(MessageFlags.CrossPost))
                                {
                                    <span class="chatlog__author-tag">SERVER</span>
                                }
                                else
                                {
                                    <span class="chatlog__author-tag">BOT</span>
                                }
                            }

                            @* Timestamp *@
                            <span class="chatlog__timestamp" title="@FormatDate(message.Timestamp, "f")"><a href="#chatlog__message-container-@message.Id">@FormatDate(message.Timestamp)</a></span>
                        </div>
                    }

                    @* Content *@
                    @if ((!string.IsNullOrWhiteSpace(message.Content) && !message.IsContentHidden()) || message.EditedTimestamp is not null)
                    {
                        <div class="chatlog__content chatlog__markdown">
                            @* Text *@
                            @if (!string.IsNullOrWhiteSpace(message.Content) && !message.IsContentHidden())
                            {
                                <span class="chatlog__markdown-preserve"><!--wmm:ignore-->@Html.Raw(await FormatMarkdownAsync(message.Content))<!--/wmm:ignore--></span>
                            }

                            @* Edited timestamp *@
                            @if (message.EditedTimestamp is not null)
                            {
                                <span class="chatlog__edited-timestamp" title="@FormatDate(message.EditedTimestamp.Value, "f")">(edited)</span>
                            }
                        </div>
                    }

                    @* Attachments *@
                    @foreach (var attachment in message.Attachments)
                    {
                        <div class="chatlog__attachment @(attachment.IsSpoiler ? "chatlog__attachment--hidden" : null)" onclick="@(attachment.IsSpoiler ? "showSpoiler(event, this)" : null)">
                            @* Spoiler caption *@
                            @if (attachment.IsSpoiler)
                            {
                                <div class="chatlog__attachment-spoiler-caption">SPOILER</div>
                            }

                            @* Attachment preview *@
                            @if (attachment.IsImage)
                            {
                                <a href="@await ResolveAssetUrlAsync(attachment.Url)">
                                    <img class="chatlog__attachment-media" src="@await ResolveAssetUrlAsync(attachment.Url)" alt="@(attachment.Description ?? "Image attachment")" title="Image: @attachment.FileName (@attachment.FileSize)" loading="lazy">
                                </a>
                            }
                            else if (attachment.IsVideo)
                            {
                                <video class="chatlog__attachment-media" controls>
                                    <source src="@await ResolveAssetUrlAsync(attachment.Url)" alt="@(attachment.Description ?? "Video attachment")" title="Video: @attachment.FileName (@attachment.FileSize)">
                                </video>
                            }
                            else if (attachment.IsAudio)
                            {
                                <audio class="chatlog__attachment-media" controls>
                                    <source src="@await ResolveAssetUrlAsync(attachment.Url)" alt="@(attachment.Description ?? "Audio attachment")" title="Audio: @attachment.FileName (@attachment.FileSize)">
                                </audio>
                            }
                            else
                            {
                                <div class="chatlog__attachment-generic">
                                    <svg class="chatlog__attachment-generic-icon">
                                        <use href="#attachment-icon"/>
                                    </svg>
                                    <div class="chatlog__attachment-generic-name">
                                        <a href="@await ResolveAssetUrlAsync(attachment.Url)">
                                            @attachment.FileName
                                        </a>
                                    </div>
                                    <div class="chatlog__attachment-generic-size">
                                        @attachment.FileSize
                                    </div>
                                </div>
                            }
                        </div>
                    }

                    @* Invites *@
                    @{
                        var inviteCodes = MarkdownParser
                            .ExtractLinks(message.Content)
                            .Select(l => l.Url)
                            .Select(Invite.TryGetCodeFromUrl)
                            .WhereNotNull()
                            .ToArray();

                        foreach (var inviteCode in inviteCodes)
                        {
                            var invite = await Context.Discord.TryGetInviteAsync(inviteCode, CancellationToken);
                            if (invite is null)
                            {
                                continue;
                            }

                            <div class="chatlog__embed">
                                <div class="chatlog__embed-invite-container">
                                    <div class="chatlog__embed-invite-title">@(invite.Channel?.IsDirect == true ? "Invite to join a group DM" : "Invite to join a server")</div>
                                    <div class="chatlog__embed-invite">
                                        <div class="chatlog__embed-invite-guild-icon-container">
                                            <img class="chatlog__embed-invite-guild-icon" src="@await ResolveAssetUrlAsync(invite.Channel?.IconUrl ?? invite.Guild.IconUrl)" alt="Guild icon" loading="lazy">
                                        </div>
                                        <div class="chatlog__embed-invite-info">
                                            <div class="chatlog__embed-invite-guild-name">
                                                <a href="https://discord.gg/@invite.Code">
                                                    @(invite.Guild.Name)
                                                </a>
                                            </div>
                                            <div class="chatlog__embed-invite-channel-name">
                                                <svg class="chatlog__embed-invite-channel-icon">
                                                    <use href="#channel-icon"></use>
                                                </svg>
                                                <span> @(invite.Channel?.Name ?? "Unknown Channel")</span>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        }
                    }

                    @* Embeds *@
                    @foreach (var embed in message.Embeds)
                    {
                        // Spotify embed
                        if (embed.TryGetSpotifyTrack() is { } spotifyTrackEmbed)
                        {
                            <div class="chatlog__embed">
                                <div class="chatlog__embed-spotify-container">
                                    <iframe class="chatlog__embed-spotify" src="@spotifyTrackEmbed.Url" width="400" height="80" allowtransparency="true" allow="encrypted-media"></iframe>
                                </div>
                            </div>
                        }
                        // YouTube embed
                        else if (embed.TryGetYouTubeVideo() is { } youTubeVideoEmbed)
                        {
                            <div class="chatlog__embed">
                                @* Color pill *@
                                @if (embed.Color is not null)
                                {
                                    <div class="chatlog__embed-color-pill" style="background-color: rgba(@embed.Color.Value.R, @embed.Color.Value.G, @embed.Color.Value.B, @embed.Color.Value.A)"></div>
                                }
                                else
                                {
                                    <div class="chatlog__embed-color-pill chatlog__embed-color-pill--default"></div>
                                }

                                <div class="chatlog__embed-content-container">
                                    <div class="chatlog__embed-content">
                                        <div class="chatlog__embed-text">
                                            @* Embed author *@
                                            @if (embed.Author is not null)
                                            {
                                                <div class="chatlog__embed-author-container">
                                                    @if (!string.IsNullOrWhiteSpace(embed.Author.IconUrl))
                                                    {
                                                        <img class="chatlog__embed-author-icon" src="@await ResolveAssetUrlAsync(embed.Author.IconProxyUrl ?? embed.Author.IconUrl)" alt="Author icon" loading="lazy" onerror="this.style.visibility='hidden'">
                                                    }

                                                    @if (!string.IsNullOrWhiteSpace(embed.Author.Name))
                                                    {
                                                        if (!string.IsNullOrWhiteSpace(embed.Author.Url))
                                                        {
                                                            <a class="chatlog__embed-author-link" href="@embed.Author.Url">
                                                                <div class="chatlog__embed-author">@embed.Author.Name</div>
                                                            </a>
                                                        }
                                                        else
                                                        {
                                                            <div class="chatlog__embed-author">@embed.Author.Name</div>
                                                        }
                                                    }
                                                </div>
                                            }

                                            @* Embed title *@
                                            @if (!string.IsNullOrWhiteSpace(embed.Title))
                                            {
                                                <div class="chatlog__embed-title">
                                                    @if (!string.IsNullOrWhiteSpace(embed.Url))
                                                    {
                                                        <a class="chatlog__embed-title-link" href="@embed.Url">
                                                            <div class="chatlog__markdown chatlog__markdown-preserve"><!--wmm:ignore-->@Html.Raw(await FormatEmbedMarkdownAsync(embed.Title))<!--/wmm:ignore--></div>
                                                        </a>
                                                    }
                                                    else
                                                    {
                                                        <div class="chatlog__markdown chatlog__markdown-preserve"><!--wmm:ignore-->@Html.Raw(await FormatEmbedMarkdownAsync(embed.Title))<!--/wmm:ignore--></div>
                                                    }
                                                </div>
                                            }

                                            @* Video player *@
                                            <div class="chatlog__embed-youtube-container">
                                                <iframe class="chatlog__embed-youtube" src="@youTubeVideoEmbed.Url" width="400" height="225"></iframe>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        }
                        // Generic image embed
                        else if (embed.Kind == EmbedKind.Image && !string.IsNullOrWhiteSpace(embed.Url))
                        {
                            var embedImageUrl =
                                embed.Image?.ProxyUrl ?? embed.Image?.Url ??
                                embed.Thumbnail?.ProxyUrl ?? embed.Thumbnail?.Url ??
                                embed.Url;

                            <div class="chatlog__embed">
                                <a href="@await ResolveAssetUrlAsync(embedImageUrl)">
                                    <img class="chatlog__embed-generic-image" src="@await ResolveAssetUrlAsync(embedImageUrl)" alt="Embedded image" loading="lazy">
                                </a>
                            </div>
                        }
                        // Generic video embed
                        else if (embed.Kind == EmbedKind.Video 
                                 && !string.IsNullOrWhiteSpace(embed.Url)
                                 // Twitch clips cannot be embedded in local HTML files
                                 && embed.TryGetTwitchClip() is null)
                        {
                            var embedVideoUrl =
                                embed.Video?.ProxyUrl ?? embed.Video?.Url ??
                                embed.Url;

                            <div class="chatlog__embed">
                                <video class="chatlog__embed-generic-video" width="@embed.Video?.Width" height="@embed.Video?.Height" controls>
                                    <source src="@await ResolveAssetUrlAsync(embedVideoUrl)" alt="Embedded video">
                                </video>
                            </div>
                        }
                        // Generic gifv embed
                        else if (embed.Kind == EmbedKind.Gifv && !string.IsNullOrWhiteSpace(embed.Url))
                        {
                            var embedVideoUrl =
                                embed.Video?.ProxyUrl ?? embed.Video?.Url ??
                                embed.Url;

                            <div class="chatlog__embed">
                                <video class="chatlog__embed-generic-gifv" width="@embed.Video?.Width" height="@embed.Video?.Height" loop onmouseover="this.play()" onmouseout="this.pause()">
                                    <source src="@await ResolveAssetUrlAsync(embedVideoUrl)" alt="Embedded gifv">
                                </video>
                            </div>
                        }
                        // Rich embed
                        else
                        {
                            <div class="chatlog__embed">
                                @* Color pill *@
                                @if (embed.Color is not null)
                                {
                                    <div class="chatlog__embed-color-pill" style="background-color: rgba(@embed.Color.Value.R, @embed.Color.Value.G, @embed.Color.Value.B, @embed.Color.Value.A)"></div>
                                }
                                else
                                {
                                    <div class="chatlog__embed-color-pill chatlog__embed-color-pill--default"></div>
                                }

                                <div class="chatlog__embed-content-container">
                                    <div class="chatlog__embed-content">
                                        <div class="chatlog__embed-text">
                                            @* Embed author *@
                                            @if (embed.Author is not null)
                                            {
                                                <div class="chatlog__embed-author-container">
                                                    @if (!string.IsNullOrWhiteSpace(embed.Author.IconUrl))
                                                    {
                                                        <img class="chatlog__embed-author-icon" src="@await ResolveAssetUrlAsync(embed.Author.IconProxyUrl ?? embed.Author.IconUrl)" alt="Author icon" loading="lazy" onerror="this.style.visibility='hidden'">
                                                    }

                                                    @if (!string.IsNullOrWhiteSpace(embed.Author.Name))
                                                    {
                                                        if (!string.IsNullOrWhiteSpace(embed.Author.Url))
                                                        {
                                                            <a class="chatlog__embed-author-link" href="@embed.Author.Url">
                                                                <div class="chatlog__embed-author">@embed.Author.Name</div>
                                                            </a>
                                                        }
                                                        else
                                                        {
                                                            <div class="chatlog__embed-author">@embed.Author.Name</div>
                                                        }
                                                    }
                                                </div>
                                            }

                                            @* Embed title *@
                                            @if (!string.IsNullOrWhiteSpace(embed.Title))
                                            {
                                                <div class="chatlog__embed-title">
                                                    @if (!string.IsNullOrWhiteSpace(embed.Url))
                                                    {
                                                        <a class="chatlog__embed-title-link" href="@embed.Url">
                                                            <div class="chatlog__markdown chatlog__markdown-preserve"><!--wmm:ignore-->@Html.Raw(await FormatEmbedMarkdownAsync(embed.Title))<!--/wmm:ignore--></div>
                                                        </a>
                                                    }
                                                    else
                                                    {
                                                        <div class="chatlog__markdown chatlog__markdown-preserve"><!--wmm:ignore-->@Html.Raw(await FormatEmbedMarkdownAsync(embed.Title))<!--/wmm:ignore--></div>
                                                    }
                                                </div>
                                            }

                                            @* Embed description *@
                                            @if (!string.IsNullOrWhiteSpace(embed.Description))
                                            {
                                                <div class="chatlog__embed-description">
                                                    <div class="chatlog__markdown chatlog__markdown-preserve"><!--wmm:ignore-->@Html.Raw(await FormatEmbedMarkdownAsync(embed.Description))<!--/wmm:ignore--></div>
                                                </div>
                                            }

                                            @* Embed fields *@
                                            @if (embed.Fields.Any())
                                            {
                                                <div class="chatlog__embed-fields">
                                                    @foreach (var field in embed.Fields)
                                                    {
                                                        <div class="chatlog__embed-field @(field.IsInline ? "chatlog__embed-field--inline" : null)">
                                                            @if (!string.IsNullOrWhiteSpace(field.Name))
                                                            {
                                                                <div class="chatlog__embed-field-name">
                                                                    <div class="chatlog__markdown chatlog__markdown-preserve"><!--wmm:ignore-->@Html.Raw(await FormatEmbedMarkdownAsync(field.Name))<!--/wmm:ignore--></div>
                                                                </div>
                                                            }

                                                            @if (!string.IsNullOrWhiteSpace(field.Value))
                                                            {
                                                                <div class="chatlog__embed-field-value">
                                                                    <div class="chatlog__markdown chatlog__markdown-preserve"><!--wmm:ignore-->@Html.Raw(await FormatEmbedMarkdownAsync(field.Value))<!--/wmm:ignore--></div>
                                                                </div>
                                                            }
                                                        </div>
                                                    }
                                                </div>
                                            }
                                        </div>

                                        @* Embed content *@
                                        @if (embed.Thumbnail is not null && !string.IsNullOrWhiteSpace(embed.Thumbnail.Url))
                                        {
                                            <div class="chatlog__embed-thumbnail-container">
                                                <a class="chatlog__embed-thumbnail-link" href="@await ResolveAssetUrlAsync(embed.Thumbnail.ProxyUrl ?? embed.Thumbnail.Url)">
                                                    <img class="chatlog__embed-thumbnail" src="@await ResolveAssetUrlAsync(embed.Thumbnail.ProxyUrl ?? embed.Thumbnail.Url)" alt="Thumbnail" loading="lazy">
                                                </a>
                                            </div>
                                        }
                                    </div>

                                    @* Embed images *@
                                    @if (embed.Images.Any())
                                    {
                                        <div class="chatlog__embed-images @(embed.Images.Count == 1 ? "chatlog__embed-images--single" : null)">
                                            @foreach (var image in embed.Images)
                                            {
                                                if (!string.IsNullOrWhiteSpace(image.Url))
                                                {
                                                    <div class="chatlog__embed-image-container">
                                                        <a class="chatlog__embed-image-link" href="@await ResolveAssetUrlAsync(image.ProxyUrl ?? image.Url)">
                                                            <img class="chatlog__embed-image" src="@await ResolveAssetUrlAsync(image.ProxyUrl ?? image.Url)" alt="Image" loading="lazy">
                                                        </a>
                                                    </div>
                                                }
                                            }
                                        </div>
                                    }

                                    @* Embed footer & icon *@
                                    @if (embed.Footer is not null || embed.Timestamp is not null)
                                    {
                                        <div class="chatlog__embed-footer">
                                            @* Footer icon *@
                                            @if (!string.IsNullOrWhiteSpace(embed.Footer?.IconUrl))
                                            {
                                                <img class="chatlog__embed-footer-icon" src="@await ResolveAssetUrlAsync(embed.Footer.IconProxyUrl ?? embed.Footer.IconUrl)" alt="Footer icon" loading="lazy">
                                            }

                                            <span class="chatlog__embed-footer-text">
                                                @* Footer text *@
                                                @if (!string.IsNullOrWhiteSpace(embed.Footer?.Text))
                                                {
                                                    @embed.Footer.Text
                                                }

                                                @if (!string.IsNullOrWhiteSpace(embed.Footer?.Text) && embed.Timestamp is not null)
                                                {
                                                    @(" • ")
                                                }

                                                @* Embed timestamp *@
                                                @if (embed.Timestamp is not null)
                                                {
                                                    @FormatDate(embed.Timestamp.Value)
                                                }
                                            </span>
                                        </div>
                                    }
                                </div>
                            </div>
                        }
                    }

                    @* Stickers *@
                    @foreach (var sticker in message.Stickers)
                    {
                        <div class="chatlog__sticker" title="@sticker.Name">
                            @if (sticker.IsImage)
                            {
                                <img class="chatlog__sticker--media" src="@await ResolveAssetUrlAsync(sticker.SourceUrl)" alt="Sticker">
                            }
                            else if (sticker.Format == StickerFormat.Lottie)
                            {
                                <div class="chatlog__sticker--media" data-source="@await ResolveAssetUrlAsync(sticker.SourceUrl)"></div>
                            }
                        </div>
                    }

                    @* Message reactions *@
                    @if (message.Reactions.Any())
                    {
                        <div class="chatlog__reactions">
                            @foreach (var reaction in message.Reactions)
                            {
                                <div class="chatlog__reaction" title="@reaction.Emoji.Code">
                                    <img class="chatlog__emoji chatlog__emoji--small" alt="@reaction.Emoji.Name" src="@await ResolveAssetUrlAsync(reaction.Emoji.ImageUrl)" loading="lazy">
                                    <span class="chatlog__reaction-count">@reaction.Count</span>
                                </div>
                            }
                        </div>
                    }
                </div>
            }
        </div>
    </div>
}
</div>